package org.news.web.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.RedisUtils;
import org.news.web.constant.NewsConstant;
import org.news.web.constant.UsersConstant;
import org.news.web.domain.News;
import org.news.web.domain.Users;
import org.news.web.domain.vo.NewsVo;
import org.news.web.domain.vo.UsersVo;
import org.news.web.mapper.NewsMapper;
import org.news.web.mapper.UsersMapper;
import org.news.web.redis.RedisConstant;
import org.news.web.service.IRecommendService;
import org.news.web.service.IUsersService;
import org.news.web.utils.NewsBehavior;
import org.news.web.utils.UserBasedCollaborativeFiltering;
import org.news.web.utils.UserBehaviorModel;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@RequiredArgsConstructor
@Service("IRecommendService")
public class RecommendServiceImpl implements IRecommendService {


    private final IUsersService usersService;

    private final UsersMapper usersMapper;


    private final NewsMapper newsMapper;

    private final NewsServiceImpl newsService;


    /**
     * 个性化推荐
     * @param authorization
     * @return
     */
    @Override
    public List<NewsVo> getRecommed(String authorization) {
//       1。 获取在redis中缓存的 当前用户的行为数据
//          通过key来获取用户信息
        UsersVo userInfo = usersService.getUserInfo(authorization);
//        获取当前用户信息的行为数据
        UserBehaviorModel userActionInfo = getUserActionInfo(userInfo.getUserId());
        if(userActionInfo == null || userActionInfo.getNewsBehaviors().size() == 0){
//            todo 随机推荐 6个新闻
           return RandomNews();
        }

//       2. 获取所有用户在redis中的行为数据
//        2.1获取所有用户的id
        List<UserBehaviorModel> userBehaviorModels = new ArrayList<>();
//        获取所有状态为活跃的用户
        List<UsersVo> users = usersMapper.selectVoList(new LambdaQueryWrapper<Users>().ne(Users::getUserId,userInfo.getUserId()).eq(Users::getStatus, UsersConstant.HY));

//        获取所有行为数据
        users.stream().forEach(
            user->{
                userBehaviorModels.add(getUserActionInfo(user.getUserId()));
            }
        );

//       进行6个相似的用户查询获取他们的新闻数据
//        小于6个就全部就行
        int k = userBehaviorModels.size() >= 6?6:userBehaviorModels.size();
        List<String> newsId = UserBasedCollaborativeFiltering.recommendNews(userActionInfo, userBehaviorModels,k);

        if(newsId == null || newsId.size() ==0){
//            暂时没有和该用户行为相似的用户 随机推荐
            return this.RandomNews();
        }


        List<NewsVo> news = newsMapper.selectVoList(new LambdaQueryWrapper<News>().in(News::getNewsId, newsId));

        newsService.setNewsAuthorName(news);
        newsService.setNewsImg(news);
//       3. 返回数据内容
        return news;
    }

    // 当前用户id的行为数据
    public UserBehaviorModel getUserActionInfo(Long userId){
        //        当前用户
        UserBehaviorModel nowUser = new UserBehaviorModel(String.valueOf(userId));
//  行为:用户id
        Set<Integer> newIds = RedisUtils.getCacheSet(RedisConstant.XIN_WEI + ":" + userId);
        if(ObjectUtil.isNull(newIds)){
            return null;
        }
//        行为:用户id:新闻id    （key value） 获取行为数据
        for (Integer newId : newIds) {
            Map<String, Integer> userToNewAction = RedisUtils.getCacheMap(RedisConstant.XIN_WEI + ":" + userId + ":" + newId);
//           添加行为
            nowUser.addNewsBehavior(new NewsBehavior(String.valueOf(newId),
                userToNewAction.getOrDefault(RedisConstant.IS_VIEW,0) == 1,
                userToNewAction.getOrDefault(RedisConstant.IS_LIKE,0) == 1,
                userToNewAction.getOrDefault(RedisConstant.IS_FAVO,0) == 1,
                userToNewAction.getOrDefault(RedisConstant.IS_COMM,0) == 1
            ));
        }

        return nowUser;
    }


    @Override
    public List<NewsVo> RandomNews(){
        //随机返回6个新闻
        List<NewsVo> newsVos = newsMapper.selectVoList(new LambdaQueryWrapper<News>().eq(News::getApplyStatus, NewsConstant.FaBu));
//       把新闻图片进行赋值
        newsService.setNewsAuthorName(newsVos);
        newsService.setNewsImg(newsVos);
        newsService.setNewsTag(newsVos);
//
        if(newsVos.size() <= 6){
            return newsVos;
        }else{
            return RandomUtil.randomEleSet(newsVos, 6).stream().toList();
        }
    }
}
